
package com.idea.rdftree;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import javax.swing.tree.TreeModel;
import javax.swing.tree.TreeNode;

//import org.idea.common.vocabularies.FILESYSTEM;

import com.hp.hpl.jena.rdf.model.Literal;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.Property;
import com.hp.hpl.jena.rdf.model.RDFNode;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.rdf.model.Statement;
import com.hp.hpl.jena.rdf.model.StmtIterator;
import com.idea.common.rdf.RdfUtils;

public class RdfNodeMap {
	private Map resources;
	private Map statements;
	private Map literals;
	private Map models;

	private RootNode rootNode;

	private TreeModel treeModel;
	private Model model;

	private Model currentModel;
	private String currentModelFilename;

	private String topModelFilename;

	public RdfNodeMap(Model model) {
		setTopModel(model);

		initMaps();

		interpret();
	}

	private void initMaps() {
		models = new HashMap();
		resources = new HashMap();
		statements = new HashMap();
		literals = new HashMap();
	}

	public void reload() {
		initMaps();
		interpret();

		Iterator iterator = models.values().iterator();

		while (iterator.hasNext()) {
			((ModelNode) iterator.next()).setDirty(true);
		}

		iterator = resources.values().iterator();

		while (iterator.hasNext()) {
			((ResourceNode) iterator.next()).setDirty(true);
		}

		iterator = statements.values().iterator();

		while (iterator.hasNext()) {
			((StatementNode) iterator.next()).setDirty(true);
		}

		iterator = literals.values().iterator();

		while (iterator.hasNext()) {
			((LiteralNode) iterator.next()).setDirty(true);
		}
	}

	public void interpret() {

		currentModel = getTopModel();
		//System.out.println("interpreting" + currentModel);
		interpret(getTopModel());
		//	rootNode = new RootNode(this);
		createRootNode();
	}

	public void createRootNode() {
		//	System.out.println("CREATING BASE ROOT NODE");
		rootNode = new RootNode(this);
	}

	private void interpret(Model sourceModel) {
		currentModel = sourceModel;
		try {
			StmtIterator iterator = sourceModel.listStatements();
			Statement statement;
			Property predicate;
			Resource subject;
			RDFNode object;

			while (iterator.hasNext()) {
				statement = (Statement)iterator.next();
				object = statement.getObject();

				addResource(statement, statement.getSubject());
				addStatement(statement);

				if (object instanceof Resource) {
					addResource((Resource) object);
				} else {
					addLiteral(statement, (Literal) object);
				}
			}
		} catch (Exception exception) {
			exception.printStackTrace();
		}
	}

	public void addResource(Resource resource) {
		addResource(null, resource);
	}

	public void addResource(Statement statement, Resource resource) {
	//	System.out.println("adding resource");
		try {
			if (!getResourceMap().containsKey(resource)) {
			/*
			    if (resource.hasProperty(FILESYSTEM.type, FILESYSTEM.Model)) {
					addChildModel(statement, resource);

				} else {
				*/
					ResourceNode resourceNode =
						new ResourceNode(this, statement, resource);
			
					getResourceMap().put(resource, resourceNode);

//				}
			}
		} catch (Exception exception) {
			exception.printStackTrace();
		}
	}

	public void removeResource(Resource resource) {
		//	MutableTreeNode node = (MutableTreeNode) resources.get(resource);
		//((MutableTreeNode) node.getParent()).remove(node);
		resources.remove(resource);
	}

	protected void addChildModel(
		Statement parentStatement,
		Resource resource) {
	    /*
	//	System.out.println("GOT A MODEL");
		String filename =
			RdfUtils
				.getFirstPropertyValue(resource, FILESYSTEM.local)
				.toString();
		Model childModel = RdfUtils.load(filename);
		currentModelFilename = filename;

		getResourceMap().put(
			resource,
			new ModelNode(this, childModel, parentStatement, resource));
		interpret(childModel);
		*/
	}

	// note model identified by resource in parent
	public void removeModel(Resource resource) {
		//	MutableTreeNode node = (MutableTreeNode) models.get(resource);
		//	((MutableTreeNode) node.getParent()).remove(node);

		models.remove(resource);
	}

	public void addStatement(Statement statement) {
		if (!statements.containsKey(statement)) {
			//	System.out.println("\nputting st " + statement);
			StatementNode statementNode = new StatementNode(this, statement);

			statements.put(statement, statementNode);

			//	System.out.println("get st " + statements.get(statement));
		}
	}

	public void removeStatement(Statement statement) {
		//MutableTreeNode node = (MutableTreeNode) statements.get(statement);
		//((MutableTreeNode) node.getParent()).remove(node);
		statements.remove(statement);
	}

	public void addLiteral(Statement statement, Literal literal) {
		if (!literals.containsKey(literal)) {
			LiteralNode literalNode = new LiteralNode(this, statement, literal);

		
			//	literalNode.setModel(currentModel);
			//	literalNode.setModelFilename(currentModelFilename);

			literals.put(literal, literalNode);
		}
	}

/*
	public void passModelToNode(RdfNode node) {
		System.out.println("CURRENT MODEL = "+currentModel);
		node.setModel(currentModel);
		node.setModelFilename(currentModelFilename);
	}
*/

	public void removeLiteral(Literal literal) {
		LiteralNode node = (LiteralNode) literals.get(literal);

	//	System.out.println("MODEL");
		//RdfUtils.show(node.getModel());
		//System.out.println("-------");

		Statement parentStatement = node.getParentStatement();

	//	System.out.println("parentStatement");
	//	RdfUtils.show(parentStatement);
	//	System.out.println("BEFORE");
	//	RdfUtils.show(node.getModel());

		try {

			node.getModel().remove(parentStatement);

		} catch (Exception exception) {
			exception.printStackTrace();
		}

		/*
		System.out.println("AFTER");
			RdfUtils.show(node.getModel());
		*/
		//	literals.remove(literal);
	//	System.out.println("REMOVED!!!!!" + literals.get(literal));
		//	node.removeFromParent();

		reload();
		((RdfTreeModel) treeModel).reload();

		//	statements.remove(parentStatement);
		/*
		MutableTreeNode node = (MutableTreeNode) literals.get(literal);
		System.out.println	("parent NODE = "+(MutableTreeNode) node.getParent());
		
		
		MutableTreeNode parent = (MutableTreeNode)node.getParent();
		if (parent != null) {
		//  parent.remove(node);
		  int i = parent.getIndex(node);
		  System.out.println("i= "+i);
		MutableTreeNode child = (MutableTreeNode)parent.getChildAt(i);
		System.out.println("child = "+child);
		parent.remove(i);
		*/

		//node.getParent().children().elementAt(node.getParent().getIndex(node));

	}

	public Map getResourceMap() {
		return resources;
	}

	public TreeNode getTreeNode(RDFNode rdfNode) {
		//if (rdfNode instanceof Statement) {
		//	return getStatementNode((Statement) rdfNode);
		//}

		if (rdfNode instanceof Resource) {
			return getResourceNode((Resource) rdfNode);
		}

		if (rdfNode instanceof Literal) {
			return getLiteralNode((Literal) rdfNode);
		}

		return null;
	}
	
	public TreeNode getTreeNode(Statement statement) {
	
			return getStatementNode(statement);
		}

	public ResourceNode getResourceNode(Resource resource) {
		Object object = resources.get(resource);

		if (object != null) {
			return (ResourceNode) object;
		}

		return null;
	}

	public StatementNode getStatementNode(Statement statement) {
		//	System.out.println("S = " + statement);
		Object object = statements.get(statement);

		//	System.out.println("object= " + object);
		if (object != null) {
			return (StatementNode) object;
		}

		return null;
	}

	/*
	        public StatementTreeNode getPropertyNode(Property property) {
	                Object object = statements.get(property);
	                if (object != null) {
	                        return (StatementTreeNode) object;
	                }
	                return null;
	        }
	*/
	public LiteralNode getLiteralNode(Literal literal) {
		Object object = literals.get(literal);

		if (object != null) {
			return (LiteralNode) object;
		}

		return null;
	}

	/**
	 * Returns the rootNode.
	 * @return RootNode
	 */
	public TreeNode getRoot() {
		return rootNode;
	}

	/**
	 * Sets the rootNode.
	 * @param rootNode The rootNode to set
	 */
	public void setRootNode(RootNode rootNode) {
		this.rootNode = rootNode;
	}

	public Set getResources() {
		return resources.keySet();
	}

	/**
	 * Returns the model.
	 * @return Model
	 */
	public Model getTopModel() {
		return model;
	}

	/**
	 * Sets the model.
	 * @param model The model to set
	 */
	public void setTopModel(Model model) {
		this.model = model;
	}

	public void setTopModelFilename(String topModelFilename) {
		this.topModelFilename = topModelFilename;
	}

	/**
	 * Returns the literals.
	 * @return HashMap
	 */
	public Map getLiterals() {
		return literals;
	}

	/**
	 * Returns the statements.
	 * @return HashMap
	 */
	public Map getStatements() {
		return statements;
	}

	/**
	 * Sets the literals.
	 * @param literals The literals to set
	 */
	public void setLiterals(HashMap literals) {
		this.literals = literals;
	}

	/**
	 * Sets the resources.
	 * @param resources The resources to set
	 */
	public void setResources(HashMap resources) {
		this.resources = resources;
	}

	/**
	 * Sets the statements.
	 * @param statements The statements to set
	 */
	public void setStatements(HashMap statements) {
		this.statements = statements;
	}
	public TreeModel getTreeModel() {
		return treeModel;
	}

	public void setTreeModel(TreeModel model) {
		treeModel = model;
	}

	public Model getCurrentModel() {
		return currentModel;
	}

	public void setCurrentModel(Model model) {
		currentModel = model;
	}

	public String getCurrentModelFilename() {
		return currentModelFilename;
	}

	public void setCurrentModelFilename(String string) {
		currentModelFilename = string;
	}

}
